Allow setting the accessible role at construction
authorEmmanuele Bassi <ebassi@gnome.org>
Mon, 13 Jul 2020 14:20:19 +0000 (15:20 +0100)
committerEmmanuele Bassi <ebassi@gnome.org>
Sun, 26 Jul 2020 19:31:15 +0000 (20:31 +0100)
Some widgets have different accessible roles depending on some
parameter, so we cannot set the role at class init time. For those
widgets, we add an "accessible-role" property to GtkAccessible, and we
allow setting it (only) at construction time.

gtk/gtkaccessible.c
gtk/gtkaccessible.h
gtk/gtkwidget.c
gtk/gtkwidget.h
gtk/gtkwidgetprivate.h

index c6e576c32951255b7c1c32470711f117ce8552bd..47bebc7543e1dab3d5ea38dd89dbba6bba99e510 100644 (file)
@@ -46,6 +46,7 @@
 
 #include "gtkatcontextprivate.h"
 #include "gtkenums.h"
+#include "gtktypebuiltins.h"
 
 #include <stdarg.h>
 
@@ -54,8 +55,27 @@ G_DEFINE_INTERFACE (GtkAccessible, gtk_accessible, G_TYPE_OBJECT)
 static void
 gtk_accessible_default_init (GtkAccessibleInterface *iface)
 {
+  GParamSpec *pspec =
+    g_param_spec_enum ("accessible-role",
+                       "Accessible Role",
+                       "The role of the accessible object",
+                       GTK_TYPE_ACCESSIBLE_ROLE,
+                       GTK_ACCESSIBLE_ROLE_WIDGET,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT_ONLY |
+                       G_PARAM_STATIC_STRINGS);
+
+  g_object_interface_install_property (iface, pspec);
 }
 
+/*< private >
+ * gtk_accessible_get_at_context:
+ * @self: a #GtkAccessible
+ *
+ * Retrieves the #GtkATContext for the given #GtkAccessible.
+ *
+ * Returns: (transfer none): the #GtkATContext
+ */
 GtkATContext *
 gtk_accessible_get_at_context (GtkAccessible *self)
 {
@@ -64,6 +84,26 @@ gtk_accessible_get_at_context (GtkAccessible *self)
   return GTK_ACCESSIBLE_GET_IFACE (self)->get_at_context (self);
 }
 
+/**
+ * gtk_accessible_get_accessible_role:
+ * @self: a #GtkAccessible
+ *
+ * Retrieves the #GtkAccessibleRole for the given #GtkAccessible.
+ *
+ * Returns: a #GtkAccessibleRole
+ */
+GtkAccessibleRole
+gtk_accessible_get_accessible_role (GtkAccessible *self)
+{
+  g_return_val_if_fail (GTK_IS_ACCESSIBLE (self), GTK_ACCESSIBLE_ROLE_WIDGET);
+
+  GtkATContext *context = gtk_accessible_get_at_context (self);
+  if (context == NULL)
+    return GTK_ACCESSIBLE_ROLE_WIDGET;
+
+  return gtk_at_context_get_accessible_role (context);
+}
+
 /**
  * gtk_accessible_update_state:
  * @self: a #GtkAccessible
index 9fe16616e5ce3d4c968af4509ae66f535aa98a2e..5b943f89a22441a78c12c98f4861c2ef10d60aad 100644 (file)
@@ -32,12 +32,15 @@ GDK_AVAILABLE_IN_ALL
 G_DECLARE_INTERFACE (GtkAccessible, gtk_accessible, GTK, ACCESSIBLE, GObject)
 
 GDK_AVAILABLE_IN_ALL
-void    gtk_accessible_update_state             (GtkAccessible      *self,
-                                                 GtkAccessibleState  first_state,
-                                                 ...);
+GtkAccessibleRole       gtk_accessible_get_accessible_role      (GtkAccessible *self);
+
+GDK_AVAILABLE_IN_ALL
+void                    gtk_accessible_update_state             (GtkAccessible      *self,
+                                                                 GtkAccessibleState  first_state,
+                                                                 ...);
 GDK_AVAILABLE_IN_ALL
-void    gtk_accessible_update_state_value       (GtkAccessible      *self,
-                                                 GtkAccessibleState  state,
-                                                 const GValue       *value);
+void                    gtk_accessible_update_state_value       (GtkAccessible      *self,
+                                                                 GtkAccessibleState  state,
+                                                                 const GValue       *value);
 
 G_END_DECLS
index 08ad5bdbce2dd0bf3d7530731f2d502a43a56151..49121957e5327f3aa78d0d3bb0c7bc75f9df7141 100644 (file)
@@ -512,7 +512,10 @@ enum {
   PROP_CSS_NAME,
   PROP_CSS_CLASSES,
   PROP_LAYOUT_MANAGER,
-  NUM_PROPERTIES
+  NUM_PROPERTIES,
+
+  /* GtkAccessible */
+  PROP_ACCESSIBLE_ROLE
 };
 
 static GParamSpec *widget_props[NUM_PROPERTIES] = { NULL, };
@@ -1335,6 +1338,8 @@ gtk_widget_class_init (GtkWidgetClass *klass)
 
   g_object_class_install_properties (gobject_class, NUM_PROPERTIES, widget_props);
 
+  g_object_class_override_property (gobject_class, PROP_ACCESSIBLE_ROLE, "accessible-role");
+
   /**
    * GtkWidget::destroy:
    * @object: the object which received the signal
@@ -1715,6 +1720,9 @@ gtk_widget_set_property (GObject         *object,
     case PROP_LAYOUT_MANAGER:
       gtk_widget_set_layout_manager (widget, g_value_dup_object (value));
       break;
+    case PROP_ACCESSIBLE_ROLE:
+      priv->accessible_role = g_value_get_enum (value);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1845,6 +1853,16 @@ gtk_widget_get_property (GObject         *object,
     case PROP_LAYOUT_MANAGER:
       g_value_set_object (value, gtk_widget_get_layout_manager (widget));
       break;
+    case PROP_ACCESSIBLE_ROLE:
+      {
+        GtkAccessibleRole role = priv->accessible_role;
+
+        if (priv->accessible_role == GTK_ACCESSIBLE_ROLE_WIDGET)
+          role = gtk_widget_class_get_accessible_role (GTK_WIDGET_GET_CLASS (widget));
+
+        g_value_set_enum (value, role);
+      }
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -2258,6 +2276,8 @@ gtk_widget_init (GTypeInstance *instance, gpointer g_class)
   priv->halign = GTK_ALIGN_FILL;
   priv->valign = GTK_ALIGN_FILL;
 
+  priv->accessible_role = GTK_ACCESSIBLE_ROLE_WIDGET;
+
   priv->width_request = -1;
   priv->height_request = -1;
 
@@ -8076,9 +8096,23 @@ gtk_widget_accessible_get_at_context (GtkAccessible *accessible)
     {
       GtkWidgetClass *widget_class = GTK_WIDGET_GET_CLASS (self);
       GtkWidgetClassPrivate *class_priv = widget_class->priv;
+      GtkAccessibleRole role;
 
-      priv->at_context =
-        gtk_at_context_create (class_priv->accessible_role, accessible);
+      /* Widgets have two options to set the accessible role: either they
+       * define it in their class_init() function, and the role applies to
+       * all instances; or an instance is created with the :accessible-role
+       * property (from GtkAccessible) set to anything other than the default
+       * GTK_ACCESSIBLE_ROLE_WIDGET value.
+       *
+       * In either case, the accessible role cannot be set post-construction.
+       */
+      if (priv->accessible_role != GTK_ACCESSIBLE_ROLE_WIDGET)
+        role = priv->accessible_role;
+      else
+        role = class_priv->accessible_role;
+
+      priv->at_context = gtk_at_context_create (role, accessible);
+      priv->accessible_role = role;
     }
 
   return priv->at_context;
@@ -12139,3 +12173,27 @@ gtk_widget_class_set_accessible_role (GtkWidgetClass    *widget_class,
   priv = widget_class->priv;
   priv->accessible_role = accessible_role;
 }
+
+/**
+ * gtk_widget_class_get_accessible_role:
+ * @widget_class: a #GtkWidgetClass
+ *
+ * Retrieves the accessible role used by the given #GtkWidget class.
+ *
+ * Different accessible roles have different states, and are rendered
+ * differently by assistive technologies.
+ *
+ * See also: gtk_accessible_get_accessible_role()
+ *
+ * Returns: the accessible role for the widget class
+ */
+GtkAccessibleRole
+gtk_widget_class_get_accessible_role (GtkWidgetClass *widget_class)
+{
+  GtkWidgetClassPrivate *priv;
+
+  g_return_val_if_fail (GTK_IS_WIDGET_CLASS (widget_class), GTK_ACCESSIBLE_ROLE_WIDGET);
+
+  priv = widget_class->priv;
+  return priv->accessible_role;
+}
index fb4d13d5c7b3d8453910e27276fdedd4cfc192cf..e3ead82e2fda4b6f82987af5e88bda3dda91cf4b 100644 (file)
@@ -980,6 +980,8 @@ void                    gtk_widget_action_set_enabled (GtkWidget  *widget,
 GDK_AVAILABLE_IN_ALL
 void                    gtk_widget_class_set_accessible_role    (GtkWidgetClass    *widget_class,
                                                                  GtkAccessibleRole  accessible_role);
+GDK_AVAILABLE_IN_ALL
+GtkAccessibleRole       gtk_widget_class_get_accessible_role    (GtkWidgetClass    *widget_class);
 
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkWidget, g_object_unref)
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkRequisition, gtk_requisition_free)
index 60e53705c023bf30149273aab486bdd801c12387..b5af950cf481594f046e3cb5eb3003d4b388ccbc 100644 (file)
@@ -193,7 +193,8 @@ struct _GtkWidgetPrivate
   char *tooltip_markup;
   char *tooltip_text;
 
-  /* Accessible context */
+  /* Accessibility */
+  GtkAccessibleRole accessible_role;
   GtkATContext *at_context;
 };